package indigo.mybatis;

import java.util.List;

import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMap;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;

public class MappedStatementTemplate {
	private String resource;
	private Configuration configuration;
	private String id;
	private Integer fetchSize;
	private Integer timeout;
	private StatementType statementType;
	private ResultSetType resultSetType;
	private SqlSource sqlSource;
	private Cache cache;
	private ParameterMap parameterMap;
	private List<ResultMap> resultMaps;
	private boolean flushCacheRequired;
	private boolean useCache;
	private boolean resultOrdered;
	private SqlCommandType sqlCommandType;
	private KeyGenerator keyGenerator;
	private String[] keyProperties;
	private String[] keyColumns;
	private String databaseId;
	private LanguageDriver lang;
	private String[] resultSets;

	public MappedStatementTemplate(MappedStatement ms) {
		setConfiguration(ms.getConfiguration());
		setId(ms.getId());
		setSqlSource(ms.getSqlSource());
		setSqlCommandType(ms.getSqlCommandType());
		setCache(ms.getCache());
		setDatabaseId(ms.getDatabaseId());
		setFetchSize(ms.getFetchSize());
		setFlushCacheRequired(ms.isFlushCacheRequired());
		setKeyColumns(ms.getKeyColumns());
		setKeyGenerator(ms.getKeyGenerator());
		setKeyProperties(ms.getKeyProperties());
		setLang(ms.getLang());
		setParameterMap(ms.getParameterMap());
		setResource(ms.getResource());
		setResultMaps(ms.getResultMaps());
		setResultOrdered(ms.isResultOrdered());
		setResultSets(ms.getResultSets());
		setResultSetType(ms.getResultSetType());
		setStatementType(ms.getStatementType());
		setTimeout(ms.getTimeout());
		setUseCache(ms.isUseCache());
	}

	public String getResource() {
		return resource;
	}

	public void setResource(String resource) {
		this.resource = resource;
	}

	public Configuration getConfiguration() {
		return configuration;
	}

	public void setConfiguration(Configuration configuration) {
		this.configuration = configuration;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public Integer getFetchSize() {
		return fetchSize;
	}

	public void setFetchSize(Integer fetchSize) {
		this.fetchSize = fetchSize;
	}

	public Integer getTimeout() {
		return timeout;
	}

	public void setTimeout(Integer timeout) {
		this.timeout = timeout;
	}

	public StatementType getStatementType() {
		return statementType;
	}

	public void setStatementType(StatementType statementType) {
		this.statementType = statementType;
	}

	public ResultSetType getResultSetType() {
		return resultSetType;
	}

	public void setResultSetType(ResultSetType resultSetType) {
		this.resultSetType = resultSetType;
	}

	public SqlSource getSqlSource() {
		return sqlSource;
	}

	public void setSqlSource(SqlSource sqlSource) {
		this.sqlSource = sqlSource;
	}

	public Cache getCache() {
		return cache;
	}

	public void setCache(Cache cache) {
		this.cache = cache;
	}

	public ParameterMap getParameterMap() {
		return parameterMap;
	}

	public void setParameterMap(ParameterMap parameterMap) {
		this.parameterMap = parameterMap;
	}

	public List<ResultMap> getResultMaps() {
		return resultMaps;
	}

	public void setResultMaps(List<ResultMap> resultMaps) {
		this.resultMaps = resultMaps;
	}

	public boolean isFlushCacheRequired() {
		return flushCacheRequired;
	}

	public void setFlushCacheRequired(boolean flushCacheRequired) {
		this.flushCacheRequired = flushCacheRequired;
	}

	public boolean isUseCache() {
		return useCache;
	}

	public void setUseCache(boolean useCache) {
		this.useCache = useCache;
	}

	public boolean isResultOrdered() {
		return resultOrdered;
	}

	public void setResultOrdered(boolean resultOrdered) {
		this.resultOrdered = resultOrdered;
	}

	public SqlCommandType getSqlCommandType() {
		return sqlCommandType;
	}

	public void setSqlCommandType(SqlCommandType sqlCommandType) {
		this.sqlCommandType = sqlCommandType;
	}

	public KeyGenerator getKeyGenerator() {
		return keyGenerator;
	}

	public void setKeyGenerator(KeyGenerator keyGenerator) {
		this.keyGenerator = keyGenerator;
	}

	public String[] getKeyProperties() {
		return keyProperties;
	}

	public void setKeyProperties(String[] keyProperties) {
		this.keyProperties = keyProperties;
	}

	public String[] getKeyColumns() {
		return keyColumns;
	}

	public void setKeyColumns(String[] keyColumns) {
		this.keyColumns = keyColumns;
	}

	public String getDatabaseId() {
		return databaseId;
	}

	public void setDatabaseId(String databaseId) {
		this.databaseId = databaseId;
	}

	public LanguageDriver getLang() {
		return lang;
	}

	public void setLang(LanguageDriver lang) {
		this.lang = lang;
	}

	public String[] getResultSets() {
		return resultSets;
	}

	public void setResultSets(String[] resultSets) {
		this.resultSets = resultSets;
	}

	public MappedStatement create() {
		MappedStatement.Builder builder = new MappedStatement.Builder(
				getConfiguration(),
				getId(),
				getSqlSource(),
				getSqlCommandType());
		return builder
				.cache(getCache())
				.databaseId(getDatabaseId())
				.fetchSize(getFetchSize())
				.flushCacheRequired(isFlushCacheRequired())
				.keyColumn(arrayToDelimitedString(getKeyColumns()))
				.keyGenerator(getKeyGenerator())
				.keyProperty(arrayToDelimitedString(getKeyProperties()))
				.lang(getLang())
				.parameterMap(getParameterMap())
				.resource(getResource())
				.resultMaps(getResultMaps())
				.resultOrdered(isResultOrdered())
				.resultSets(arrayToDelimitedString(getResultSets()))
				.resultSetType(getResultSetType())
				.statementType(getStatementType())
				.timeout(getTimeout())
				.useCache(isUseCache())
				.build();
	}

	private static String arrayToDelimitedString(String[] in) {
		return in != null && in.length > 0 ? String.join(",", in) : null;
	}
}
